local function assertFunc(func)
	return assert(func, '不支持该函数')
end

local function getRootExecCallback(func)
	return function(...)
		local args = table.pack(...)
		local func = assertFunc(func)
		local n = args.n + 1
		args[n] = true
		return func(table.unpack(args, 1, n))
	end
end

-- 只有一个静态参数的闭包
local function staticArgClosure1(func, p1)
	return function()
		local func = assertFunc(func)
		return func(p1)
	end
end

local function getFunctionMap()
	local map = {
		['选择进程'] = checkPkg,
		['执行命令'] = getRootExecCallback(string.exec),
		['转文本'] = tostring,
		['导入'] = import,
		['加载模块'] = require,
		['禁止录屏'] = staticArgClosure1(setScreenshots, true),
		['解除禁止录屏'] = staticArgClosure1(setScreenshots, false),
		['禁止XP框架'] = checkXposed,
		['本地储存'] = storages.create,
		['我的储存'] = functions.singleton(staticArgClosure1(storages.create, '我的储存')),
		['加载脚本'] = load,
		['执行代码'] = function(code, ...)
			local func = assert(load(code))
			return func(...)
		end,
		['加载脚本文件'] = loadfile,
		['执行脚本'] = function(path, ...)
			local func = assert(loadfile(path))
			return func(...)
		end,
		['保护调用'] = pcall,
		['选择参数'] = select,
		['参数数量'] = function(...)
			return select('#', ...)
		end,
		['数据类型'] = type,
		['打印'] = print,
	
		['绘制文本'] = draw.text,
	
		['QQ聊天'] = qq.join,
		['加群'] = qq.joinGroup,
	
		['获取屏幕宽'] = device.getWidth,
		['获取屏幕高'] = device.getHeight,
		['获取IMEI'] = device.getimei,
	
		['定时任务'] = timers.setInterval,
		['取消定时任务'] = timers.clearInterval,
		['一次性定时任务'] = timers.setTimeout,
		['取消一次性定时任务'] = timers.clearTimeout,
	
		['获取多线程'] = luajava.getThread,
		['启动多线程'] = luajava.startThread,
	
		['多线程回调'] = functions.thread,
		['函数同步回调'] = functions.synchronized,
		['函数单例回调'] = functions.singleton,
	
		['退出'] = os.exit,
		['时间戳'] = os.time,
	
		['随机数'] = math.random,
	
		['启动应用'] = app.start,
		['打开网址'] = app.openUrl,
		['结束程序'] = app.exit,
		['应用名'] = app.getName,
		['应用安装包'] = app.getPath,
		['应用图标'] = app.loadIcon,
		['安装应用'] = app.install,
		['卸载应用'] = app.uninstall,
		['强制安装应用'] = getRootExecCallback(app.install),
		['强制卸载应用'] = getRootExecCallback(app.uninstall),
		['运行列表'] = app.runList,
	
		['写出文件'] = file.write,
		['写出临时文件'] = file.writeTemp,
		['读取文件'] = file.read,
		['删除文件'] = file.delete,
		['删除目录'] = file.rmdir,
		['创建目录'] = file.mkdirs,
		['强制删除'] = getRootExecCallback(file.rm),
		['文件大小'] = file.length,
		['文件名称'] = file.getName,
		['文件目录'] = file.getdir,
		['文件重命名'] = os.rename,
		['附加文件路径'] = file.appendPath,
		['改文件名'] = file.changeName, -- 只是返回修改后的路径
		['改文件后缀名'] = file.changeExtension, -- 只是返回修改后的路径
		['改文件权限'] = file.chmod,
		['文件类型'] = file.type,
		['文件信息'] = file.info,
		['文件前缀'] = file.prefix,
		['文件后缀'] = file.suffix,
		['文件时间'] = file.lastTime,
		['文件MD5'] = file.md5,
		['文件哈希值'] = file.md,
		['打开文件'] = file.open, -- 调用系统接口
		['上传文件'] = http.upload,
		['遍历目录'] = file.traverseDir,
		['下载文件'] = file.download,
		['缓存文件'] = file.checkUrl,
		['文件是否存在'] = file.exists,
		['是否为文件'] = file.isFile,
		['是否为目录'] = file.isDir,
		['复制文件'] = file.copy,
		['复制目录'] = file.cp,
		['移动文件'] = file.move,
		['移动目录'] = file.mv,
		['执行文件'] = file.exec,
		['执行二进制'] = getRootExecCallback(file.cpp),
	
		['开头是否为'] = string.startsWith,
		['结尾是否为'] = string.endsWith,
		['去首尾空'] = string.trim,
		['语音'] = string.toMusic,
		['转十六进制'] = string.bin2hex,
		['十六进制转文本'] = string.hex2bin,
		['切割文本'] = string.split,
		['解析JSON'] = json.decode,
		['URL编码'] = string.enUrl,
		['URL解码'] = string.deUrl,
		['随机文本'] = string.random,
		['随机MD5'] = string.randomMD5,
		['异或文本'] = string.xor,
	
		['安装判断'] = gg.isPackageInstalled,
		['设置配置'] = gg.setConfig,
		['获取配置'] = gg.getConfig,
		['获取剪贴板'] = gg.getClipboard,
		['写入剪切板'] = gg.copyText,
		['获取其它修改器'] = gg.getGG,
		['设置进程'] = gg.setProcess,
		['获取进程'] = gg.getProcess,
		['请求网络'] = gg.makeRequest,
		['吐司'] = gg.toast,
		['提示'] = gg.alert,
		['带标题提示'] = gg.alert2,
		['提示HTML'] = gg.htmlAlert,
		['音乐'] = gg.playMusic,
		['视频'] = gg.playVideo,
		['延时'] = gg.sleep,
		['搜索'] = gg.searchNumber,
		['获取搜索数量'] = gg.getResultCount,
		['清空搜索'] = gg.clearResults,
		['清空列表'] = gg.clearList,
		['改善'] = gg.refineNumber,
		['修改'] = gg.editAll,
		['复制内存'] = gg.copyMemory,
		['选择单个'] = gg.choice,
		['选择多个'] = gg.multiChoice,
		['带提示输入'] = gg.prompt,
		['设置内存'] = gg.setRanges,
		['获取结果'] = gg.getResults,
		['搜索结果'] = function()
			return gg.getResults(gg.getResultCount())
		end,
		['杀死其它修改器'] = gg.loopKillGG,
		['当前文件'] = gg.getFile,
		['界面是否可见'] = gg.isVisible,
		['设置界面可见'] = gg.setVisible,
		['显示界面'] = staticArgClosure1(gg.setVisible, true),
		['隐藏界面'] = staticArgClosure1(gg.setVisible, false)
	}
	
	local fix = {
		['转字符串'] = '转文本',
		['语音播报'] = '语音',
		['播放语音'] = '语音',
		['播放音乐'] = '音乐',
		['播放视频'] = '视频',
		['睡眠'] = '延时',
		['杀死其它GG'] = '杀死其它修改器',
		['打开网站'] = '打开网址',
		['当前脚本'] = '当前文件',
		['获取目录'] = '文件目录',
		['应用名称'] = '应用名',
		['文件下载'] = '下载文件',
		['文件时间戳'] = '文件时间',
		['编码网址'] = 'URL编码',
		['吐丝'] = '吐司',
		['获取其它GG'] = '获取其它修改器',
		['提示2'] = '带标题提示',
		['输出'] = '打印'
	}
	
	for k, v in pairs(fix) do
		map[k] = map[v]
	end
	
	return map
end

local function mapToGlobal(map)

	pcall(function()
		local t = {}
		for k, v in pairs(map) do
			if isString(k) then
				t[#t + 1] = string.format('%s=%q', k, k)
			end
		end
		local str = string.format('return {%s}', table.concat(t, ','))
		local fix = assert(load(str, ''))()

		for k, v in pairs(fix) do
			if map[k] == nil then
				_ENV[k] = map[v]
			end
		end
	end)

	for k, v in pairs(map) do
		_ENV[k] = v
	end

	return map
end

local initMap = {
	['中文函数'] = function(p1)
		if not isTable(p1) then
			p1 = getFunctionMap()
		end
		return mapToGlobal(p1)
	end
}

return mapToGlobal(initMap)
